<template>
  <div id="map"></div>
  <el-button type="primary" @click="handleSearch" v-if="markValue"
    >查询</el-button
  >
</template>

<script setup>
import { onMounted, watch, ref } from 'vue'
import { Map, View, Overlay } from 'ol'
import 'ol/ol.css'
//pinia
import { storeToRefs } from 'pinia'
import { useOlStore } from '@/stores/openlayer.js'
//从pinia导入需要的变量
const store = useOlStore()
const { city, vecValue, zoomLevel, markValue, searchPoint, clearSearchFlag } =
  storeToRefs(store)

//ol
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import GeoJSON from 'ol/format/GeoJSON'
import { Style, Fill, Stroke, Circle, Text } from 'ol/style'
// import Style from 'ol/style/Style'
// import Fill from 'ol/style/Fill'
// import Stroke from 'ol/style/Stroke'
import Draw from 'ol/interaction/Draw'
import { getLength, getArea, getDistance } from 'ol/sphere'
import Icon from 'ol/style/Icon'
import { Cluster } from 'ol/source'
// import { Circle } from 'ol/style'
import ol_layer_AnimatedCluster from 'ol-ext/layer/AnimatedCluster'
import {
  pointsWithinPolygon,
  point as turfPoint,
  polygon,
  featureCollection,
} from '@turf/turf'

let map

onMounted(() => {
  const gaodeLayer = new TileLayer({
    source: new XYZ({
      url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
    }),
  })
  map = new Map({
    target: 'map',
    view: new View({
      center: [108.9422, 34.2611],
      // center: [116.397428, 39.90816],
      projection: 'EPSG:4326',
      zoom: zoomLevel.value,
    }),
    layers: [gaodeLayer],
  })
  //监听view的变化
  let view = map.getView()
  view.on('change', (e) => {
    // console.log(e)
    // console.log(view.getZoom())
    zoomLevel.value = view.getZoom()
  })
})
// watch(city, vecValue, markValue, { deep: true })

//根据adcode获取城市的矢量数据的方法
//需要加个把之前的图层清空的方法
let citysLayer = null
const getCityVector = (adcode) => {
  // if (citysLayer) map.removeLayer(citysLayer)
  if (citysLayer) citysLayer.getSource().clear()
  citysLayer = new VectorLayer({
    source: new VectorSource({
      url: `https://geo.datav.aliyun.com/areas_v3/bound/${adcode}.json`,
      format: new GeoJSON(),
    }),
    style: new Style({
      fill: new Fill({
        color: 'rgba(255,0,0, 0.5)',
      }),
      stroke: new Stroke({
        color: '#000',
      }),
    }),
  })

  map.addLayer(citysLayer)
}
//获取中心点的方法
let cityCenter = ref([])
const getCityCenter = (adcode) => {
  return fetch(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}.json`)
    .then((res) => res.json())
    .then((data) => {
      //   console.log(data[0].properties.center)
      //   console.log(data.features[0].properties.center)
      return data.features[0].properties.center
    })
}

// 监听city变化，更新中心点和缩放级别
watch(
  city,
  //需要等待cityCenter获取到值再更新视图
  async () => {
    // console.log(city.value)
    getCityVector(city.value.adcode)
    cityCenter.value = await getCityCenter(city.value.adcode)
    // console.log(cityCenter.value)
    const view = map.getView()
    zoomLevel.value = 8
    view.animate({
      center: cityCenter.value,
      zoom: zoomLevel.value,
      duration: 1000,
    })
  },
  { deep: true }
)

//缩放的功能
// 监听缩放的变化，移除城市的图层
watch(zoomLevel, (value) => {
  if (value >= 10) {
    citysLayer.setVisible(false)
  } else {
    //恢复城市图层
    citysLayer.setVisible(true)
  }
})

//监听map的change:view
// map.on('change:view', (e) => {
//   console.log(e)
// })

//绘图的功能
//测距和算面积的方法
// 里面也有很多重复的,后面尝试提取出来
let overlay = null
let overlayElement = null
const lengthOrArea = (draw, geometry, drawLayer) => {
  if (!overlay) {
    // 创建overlay实例
    overlay = new Overlay({})
    overlayElement = document.createElement('P')
    overlayElement.className = 'overlay'
    document.body.appendChild(overlayElement)
    overlay.setElement(overlayElement)
    map.addOverlay(overlay)
  }

  //线:计算长度
  if (geometry == 'LineString') {
    //这个清空方式有问题,在下一次绘画的时候会找不到overlayElement
    //在最上面申明变量
    // draw.on('drawstart', () => {
    //   // 清空之前的测距结果
    //   drawLayer.getSource().clear()
    //   const flag = document.querySelector('.overlay')
    //   if (flag) {
    //     overlayElement.parentNode.removeChild(overlayElement)
    //   }
    // })

    // 清除之前画的方法,暂时不用,应该是在清除选项里面
    // draw.on('drawstart', () => {
    //   drawLayer.getSource().clear()
    //   overlayElement.innerHTML = ''
    //   overlay.setPosition(undefined)
    // })
    draw.on('drawend', (e) => {
      let feature = e.feature
      let geom = feature.getGeometry()
      let length = getLength(geom, { projection: 'EPSG:4326' })
      length = (length / 1000).toFixed(2)
      overlayElement.innerHTML = `长度：${length}km`
      let coordinates = geom.getLastCoordinate()
      overlay.setPosition(coordinates)
    })
  } else if (geometry == 'Polygon') {
    //面:计算面积
    // console.log('多边形')
    draw.on('drawend', (e) => {
      let feature = e.feature
      let geom = feature.getGeometry()
      let area = getArea(geom, { projection: 'EPSG:4326' })
      // console.log(area)
      if (area >= 1000000) {
        area = (area / 1000000).toFixed(2)
        overlayElement.innerHTML = `面积:${area}km²`
      } else {
        area = area.toFixed(2)
        overlayElement.innerHTML = `面积:${area}m²`
      }
      let coordinates = geom.getLastCoordinate()
      overlay.setPosition(coordinates)
    })
  } else if (geometry == 'Circle') {
    //圆:计算面积
    draw.on('drawend', (e) => {
      let feature = e.feature
      let geom = feature.getGeometry()
      let radius = getRadius(geom)
      let area = Math.PI * radius * radius
      if (area >= 1000000) {
        area = (area / 1000000).toFixed(2)
        overlayElement.innerHTML = `面积:${area}km²`
      } else {
        area = area.toFixed(2)
        overlayElement.innerHTML = `面积:${area}m²`
      }
      let coordinates = geom.getLastCoordinate()
      overlay.setPosition(coordinates)
    })
  }
}

//获取半径的方法
function getRadius(geom) {
  //获取中心点坐标
  const center = geom.getCenter()
  //获取半径的度数
  const radiusDeg = geom.getRadius()
  // 生成一个圆的边缘点 中心点x+半径 和中心点统一水平位置
  const edgePoint = [center[0] + radiusDeg, center[1]]
  // 计算圆心和边缘点的距离即为半径
  return getDistance(center, edgePoint)
}

// 监听vecValue变化，绘制矢量图层
let drawLayer = null
let drawLayers = []
let draw = null
watch(vecValue, (value) => {
  //太多了,很多重复了,后面尝试提取成方法
  // if (!value) return
  // clearAllDraw(mark, markLayer, markLayers, markValue)
  clearMarker()
  //画线
  if (value == 'LineString') {
    // 切换有问题,应该要先判断是否有之前的图层,然后清除,再添加新的图层
    if (draw) {
      map.removeInteraction(draw)
    }
    drawLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({
          color: 'red',
          width: 2,
        }),
      }),
    })
    drawLayers.push(drawLayer)
    map.addLayer(drawLayer)
    draw = new Draw({
      source: drawLayer.getSource(),
      type: value,
    })
    map.addInteraction(draw)
    lengthOrArea(draw, value, drawLayer)
  } else if (value == 'Polygon') {
    //画多边形
    if (draw) {
      map.removeInteraction(draw)
    }
    drawLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({
          color: '#000',
          width: 2,
        }),
        fill: new Fill({
          color: 'rgba(255,0,0, 0.5)',
        }),
      }),
    })
    drawLayers.push(drawLayer)
    map.addLayer(drawLayer)
    draw = new Draw({
      source: drawLayer.getSource(),
      type: value,
    })
    map.addInteraction(draw)
    lengthOrArea(draw, value, drawLayer)
  } else if (value == 'Circle') {
    //画圆
    if (draw) {
      map.removeInteraction(draw)
    }
    drawLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({
          color: '#000',
          width: 2,
        }),
        fill: new Fill({
          color: 'rgba(255,0,0, 0.5)',
        }),
      }),
    })
    drawLayers.push(drawLayer)
    map.addLayer(drawLayer)
    draw = new Draw({
      source: drawLayer.getSource(),
      type: value,
    })
    map.addInteraction(draw)
    lengthOrArea(draw, value, drawLayer)
  } else if (value == 'free') {
    if (draw) {
      map.removeInteraction(draw)
    }
    drawLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({
          color: 'red',
          width: 2,
        }),
      }),
    })
    drawLayers.push(drawLayer)
    map.addLayer(drawLayer)
    draw = new Draw({
      source: drawLayer.getSource(),
      type: 'LineString',
      freehand: true,
    })
    map.addInteraction(draw)
    // lengthOrArea(draw, value, drawLayer)
  } else if (value == 'clear') {
    //上面画图的时候每次都是new一个新的图层,直接清除不行
    clearVector()
    // console.log(drawLayers)
  }
})

/// 清理矢量绘图函数
const clearVector = () => {
  if (draw) {
    map.removeInteraction(draw)
    draw = null
  }
  if (drawLayers && drawLayers.length) {
    drawLayers.forEach((layer) => map.removeLayer(layer))
    drawLayers = []
  }
  if (overlay) {
    map.removeOverlay(overlay)
    if (overlayElement && overlayElement.parentNode) {
      overlayElement.parentNode.removeChild(overlayElement)
    }
    overlay = null
    overlayElement = null
  }
}

// 清理标记绘图函数
const clearMarker = () => {
  if (marker) {
    map.removeInteraction(marker)
    marker = null
  }
  if (markLayers && markLayers.length) {
    markLayers.forEach((layer) => map.removeLayer(layer))
    markLayers = []
  }
}

//监听markValue变化，绘制标注图层
let markLayer = null
let markLayers = []
let marker = null
let rawlayers = ref([]) //用来存储原始的数据,后面拉框查询用
watch(markValue, (value) => {
  // if (!value) return
  // clearAllDraw(draw, drawLayer, drawLayers, vecValue)
  clearVector()
  if (value == 'park') {
    //停车场
    if (marker) {
      map.removeInteraction(marker)
    }
    markLayer = new VectorLayer({
      source: new VectorSource(),
      // zIndex: 999,
      style: new Style({
        image: new Icon({
          src: '/park.png',
          width: 50,
          anchor: [0.5, 1],
        }),
      }),
    })

    // markLayer = getClusterLayer(markLayer, 'park')
    rawlayers.value.push({ label: `${value}`, sourece: markLayer.getSource() })
    markLayers.push(getClusterLayer(markLayer, 'park'))
    map.addLayer(getClusterLayer(markLayer, 'park'))
    marker = new Draw({
      source: markLayer.getSource(),
      type: 'Point',
    })
    map.addInteraction(marker)
  } else if (value == 'hospital') {
    //医院
    if (marker) {
      map.removeInteraction(marker)
    }
    markLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        image: new Icon({
          src: '/hospital.png',
          width: 50,
          anchor: [0.5, 1],
        }),
      }),
    })
    // rawlayers.value[value] = markLayer.getSource()
    rawlayers.value.push({ label: `${value}`, sourece: markLayer.getSource() })

    markLayers.push(getClusterLayer(markLayer, 'hospital'))
    map.addLayer(getClusterLayer(markLayer, 'hospital'))
    marker = new Draw({
      source: markLayer.getSource(),
      type: 'Point',
    })
    map.addInteraction(marker)
  } else if (value == 'charger') {
    //充电站
    if (marker) {
      map.removeInteraction(marker)
    }
    markLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        image: new Icon({
          src: '/charger.png',
          width: 50,
          anchor: [0.5, 1],
        }),
      }),
    })
    // rawlayers.value[value] = markLayer.getSource()
    rawlayers.value.push({ label: `${value}`, sourece: markLayer.getSource() })

    markLayers.push(getClusterLayer(markLayer, 'charger'))
    map.addLayer(getClusterLayer(markLayer, 'charger'))
    marker = new Draw({
      source: markLayer.getSource(),
      type: 'Point',
    })
    map.addInteraction(marker)
  } else if (value == 'bus') {
    //公交站
    if (marker) {
      map.removeInteraction(marker)
    }
    markLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        image: new Icon({
          src: '/bus.png',
          width: 50,
          anchor: [0.5, 1],
        }),
      }),
    })
    // rawlayers.value[value] = markLayer.getSource()
    rawlayers.value.push({ label: `${value}`, sourece: markLayer.getSource() })

    markLayers.push(getClusterLayer(markLayer, 'bus'))
    map.addLayer(getClusterLayer(markLayer, 'bus'))
    marker = new Draw({
      source: markLayer.getSource(),
      type: 'Point',
    })
    map.addInteraction(marker)
  }
})

//聚合图的方法
const getClusterLayer = (layer, iconname) => {
  //1设置聚合数据源
  const clusterSource = new Cluster({
    source: layer.getSource(),
    style: layer.getStyle(),
    features: layer.getSource().getFeatures(),
    distance: 80, //聚合的距离
  })
  //2.设置动画
  const clusterLayer = new ol_layer_AnimatedCluster({
    name: 'Cluster',
    source: clusterSource,
    animationDuration: 700, //动画时间
    style: clusterStyle(), //调用函数来判断
  })
  //style的函数
  function clusterStyle() {
    return (f) => {
      const features = f.get('features')
      //排除刚点击的时候的情况
      const size = features ? features.length : 0
      const style = new Style()
      if (size == 1) {
        // const feature = features[0]
        style.setImage(
          new Icon({
            src: `./${iconname}.png`,
            width: 50,
            anchor: [0.5, 1],
          })
        )
      } else {
        // 聚合点使用圆形+数字
        style.setImage(
          new Circle({
            radius: 15,
            fill: new Fill({ color: 'rgba(0, 255, 0, 0.8)' }),
            stroke: new Stroke({ color: 'yellow', width: 2 }),
          })
        )
        style.setText(
          new Text({
            text: size.toString(),
            fill: new Fill({
              color: '#fff',
              font: 'bold 14px sans-serif',
            }),
          })
        )
      }
      return style
    }
  }
  return clusterLayer
}

//拉框查询的功能
// 拉框的画笔
let searchDraw = null
let searchLayer = null
let handleSearchDraw = null
let pointCollection
const handleSearch = () => {
  clearSearchDraw()
  if (searchDraw) {
    map.removeInteraction(searchDraw)
    if (handleSearchDraw) {
      searchDraw.un('drawend', handleSearchDraw)
    }
  }
  // const allMarkPoints = rawlayers.map((layer) => layer.features)
  const allFeatures = []
  rawlayers.value.forEach((item) => {
    item.sourece.getFeatures().forEach((feature) => {
      const geom = feature.getGeometry()
      if (geom) {
        const coords = geom.getCoordinates()
        allFeatures.push(turfPoint(coords, { label: item.label }))
      }
    })
  })
  // console.log(allFeatures)
  pointCollection = featureCollection(allFeatures)
  // console.log(pointCollection)
  clearMarker()
  searchLayer = new VectorLayer({
    source: new VectorSource(),
    style: new Style({
      fill: new Fill({
        color: 'rgba(0,0,0,0.5)',
      }),
    }),
  })
  map.addLayer(searchLayer)
  searchDraw = new Draw({
    type: 'Polygon',
    source: searchLayer.getSource(),
  })
  map.addInteraction(searchDraw)
  handleSearchDraw = e
  //
  searchDraw.on('drawend', (e) => {
    let feature = e.feature
    let geom = feature.getGeometry()
    let _polygon = polygon(geom.getCoordinates())
    searchPoint.value = pointsWithinPolygon(pointCollection, _polygon)
    // console.log(searchPoint.value)

    // console.log(allFeatures)
  })
}
// 监听清理标志变化
watch(clearSearchFlag, () => {
  clearSearchDraw()
})
// 清理拉框查询的函数
const clearSearchDraw = () => {
  if (searchDraw) {
    map.removeInteraction(searchDraw)
    searchDraw = null
  }
  if (searchLayer) {
    map.removeLayer(searchLayer)
    searchLayer = null
  }
  if (handleSearchDraw) {
    handleSearchDraw = null
  }
  pointCollection = null
}
</script>

<style lang="scss" scoped>
#map {
  width: 100%;
  height: 100%;
}

:deep(.overlay) {
  // width: 20px;
  // height: 10px;
  background: white;
  color: black;
  border: 1px solid black;
  padding: 10px;
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
}
.el-button {
  position: fixed;
  top: 80px;
  left: 50px;
}
</style>
